﻿/*-----------------------------------------------
// File: BattleSkill.cs 
// Description: 
// Author: Shaobing	492057342@qq.com
-----------------------------------------------*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace Battle.View
{
    public class BattleSkill
    {
        #region Dict Data
        public string HSId;
        public SkillType skillType;
        public string heroId
        {
            get { return bc.heroId; }
        }
        public int level;

        public string animName;
        public float animDuration;

        protected List<ParticleData> effectDatas = new List<ParticleData>();
        public SkillCastSelectPointRule selectRule;
        public double selectRuleArgs;

        public AttackCameraRule attackCameraRule;
        public string skillAudio;
        public SkillAudioCtrl audioCtrl;
        #endregion

        #region InstData
        public enum SkillStatus
        {
            None,
            Ready,          // 技能可以释放
            Wait,           // 技能已经进入释放队列，但还没开始释放
            Doing,          // 技能正在释放
            Done,           // 技能释放结束
            Limit,          // 技能收到限制，不能释放
        }

        protected SkillStatus _status = SkillStatus.None;
        public SkillStatus status
        {
            get
            {
                return _status;
            }
        }

        protected BattleCharacter bc = null;
        public BattleCharacter GetOwnBC() { return bc; }
        public string heroUid
        {
            get { return bc.uniqueId; }
        }
        public int currentCD = 0;
        public bool IsCasted;
        public bool IsPressed;

        /// <summary>
        /// BUFF, CD影响
        /// </summary>
        public bool isCanCast;
        #endregion

        #region Data
        public BattleSkill(BattleActorSkillData skill, BattleCharacter _bc)
        {
            bc = _bc;
            SetData(skill);
            IsCasted = false;
            IsPressed = false;
            isLoadComplete = false;
            audioCtrl = new SkillAudioCtrl(this);
        }

        void SetData(BattleActorSkillData skill)
        {
            HSId = skill.skillId;
            skillType = (SkillType)skill.skillIndex;
            currentCD = 0;
            isCanCast = true;
            var ds = Dict.Blo.DictHeroSkillBlo.GetTalbeSkill(HSId);
            skillAudio = ds.SkillAudio;
            animName = ds.AniName;
            animDuration = (float)ds.Duration;
            attackCameraRule = (AttackCameraRule)ds.CameraRule;
            effectDatas = new List<ParticleData>();
            for (int i = 0; i < ds.Effect_array.Length; ++i) 
            {
                if (!string.IsNullOrEmpty(ds.Effect_array[i]))
                {
                    effectDatas.Add(ParticleData.CreateParticleData(ds.Effect_array[i], ds.EffBone_array[i]));
                }
            }
            selectRule = (SkillCastSelectPointRule)ds.SkillCastPointSelectRule;
            selectRuleArgs = ds.SCPSelectArgs;
            var dsrs = Dict.Blo.DictHeroSkillBlo.GetTableSkillCastByHSId(HSId);
            releases = new List<BattleSkillRelease>();
            foreach (var dsr in dsrs)
            {
                releases.Add(new BattleSkillRelease(dsr, this));
            }
            releases.Sort(delegate (BattleSkillRelease x, BattleSkillRelease y)
            {
                return x.releaseTime.CompareTo(y.releaseTime);
            });

            Ready();
        }

        void SetData(ProtoBuf.Message.ActorSkill skill)
        {
            HSId = skill.HSId;
            skillType = (SkillType)skill.skillType;
            level = skill.level;
            this.currentCD = skill.cd;
            this.isCanCast = skill.cancast == 0 ? false : true;
            var ds = Dict.Blo.DictHeroSkillBlo.GetTalbeSkill(HSId);
            skillAudio = ds.SkillAudio;
            animName = ds.AniName;
            animDuration = (float)ds.Duration;
            attackCameraRule = (AttackCameraRule)ds.CameraRule;
            effectDatas = new List<ParticleData>();
            for (int i = 0; i < ds.Effect_array.Length; ++i)
            {
                if (!string.IsNullOrEmpty(ds.Effect_array[i]))
                {
                    effectDatas.Add(ParticleData.CreateParticleData(ds.Effect_array[i], ds.EffBone_array[i]));
                }
            }
            selectRule = (SkillCastSelectPointRule)ds.SkillCastPointSelectRule;
            selectRuleArgs = ds.SCPSelectArgs;
            var dsrs = Dict.Blo.DictHeroSkillBlo.GetTableSkillCastByHSId(HSId);
            releases = new List<BattleSkillRelease>();
            foreach (var dsr in dsrs)
            {
                releases.Add(new BattleSkillRelease(dsr, this));
            }
            releases.Sort(delegate (BattleSkillRelease x, BattleSkillRelease y)
            {
                return x.releaseTime.CompareTo(y.releaseTime);
            });

            if (skill.cancast == 0)
            {
                Limit();
            }
            else
            {
                Ready();
            }
        }

        /// <summary>
        /// 数据刷新 
        /// </summary>
        /// <param name="skill"></param>

        /// <summary>
        /// 刷新数据
        /// </summary>
        /// <param name="skill"></param>
        public void Refresh(BattleActorSkillData skill)
        {
            SetData(skill);
            IsCasted = false;
            IsPressed = false;
        }

        public void Refresh(ProtoBuf.Message.ActorSkill skill)
        {
            SetData(skill);
            IsCasted = false;
            IsPressed = false;
        }

        #endregion

        #region LoadResource

        protected bool isLoadComplete = false;
        public bool LoadComplete() { return isLoadComplete; }
        public virtual IEnumerator LoadResource()
        {
            //System.DateTime dt = System.DateTime.Now;
            int taskCount = 0;
            // 加载技能施法特效
            foreach (var effectData in effectDatas)
            {
                ParticleFactory.RegistParticle(effectData.resUrl, () => { taskCount--; });
                taskCount++;
            }
            // 加载技能release
            foreach (var release in releases)
            {
                BattleViewCtrl.GetInstance().StartCoroutine(release.LoadResource());
            }

            // 加载音效
            if (!string.IsNullOrEmpty(skillAudio))
            {
                
                BattleViewCtrl.GetInstance().StartCoroutine(AudioManager.Instance.LoadAudioResource(skillAudio, () =>
                {
                    taskCount--;
                }));
                taskCount++;
            }

            while (taskCount > 0)
            {
                yield return null;
            }
            while (!IsReleaseLoadComplete())
            {
                yield return null;
            }
            //Debug.Log(GetOwnBC().heroName + " skill " + HSId + " load cost time " + (System.DateTime.Now - dt).TotalMilliseconds);
            isLoadComplete = true;
        }

        protected bool IsReleaseLoadComplete()
        {
            foreach (var release in releases)
            {
                if (!release.LoadComplete())
                {
                    return false;
                }
            }
            return true;
        }

        public virtual void UnloadResource()
        {
            foreach (var effectData in effectDatas)
            {
                ParticleFactory.UnRegistParticle(effectData.resUrl);
            }
            foreach (var release in releases)
            {
                release.UnloadResource();
            }
            if (!string.IsNullOrEmpty(skillAudio))
            {
                AudioManager.Instance.UnloadAudioResource(skillAudio);
            }
        }

        #endregion

        #region SkillRelease
        public List<BattleSkillRelease> releases = new List<BattleSkillRelease>();
        public BattleSkillRelease GetSkillRelease(string HSRId)
        {
            foreach (var release in releases)
            {
                if (release.HSRId == HSRId)
                    return release;
            }
            return null;
        }
        public BattleSkillRelease GetLastSkillRelease()
        {
            return releases[releases.Count - 1];
        }

        #endregion

        #region Skill Play
        List<ParticleObj> curEffectObjs = new List<ParticleObj>();
        public void PlaySkillAnimation()
        {
            bc.anim.Play(animName, WrapMode.Once);
            foreach (var obj in effectDatas)
            {
                var particle = bc.PlayParticle(obj, false);
                curEffectObjs.Add(particle);
            }
        }

        public void PlaySkillAudio()
        {
            audioCtrl.Start(skillAudio);
        }
        public void StopSkillAudio()
        {
            audioCtrl.Stop();
        }

        public void ForceHideSkillParticle()
        {
            foreach (var obj in curEffectObjs)
            {
                obj.Recycle();
            }
            curEffectObjs.Clear();
        }
        #endregion


        public virtual void Ready()
        {
            _status = SkillStatus.Ready;
            this.IsPressed = false;
            this.IsCasted = false;
        }

        public virtual void Limit()
        {
            _status = SkillStatus.Limit;
            this.IsPressed = false;
            this.IsCasted = false;
        }

        public virtual void Enqueue()
        {
            _status = SkillStatus.Wait;
            this.IsPressed = true;
            BattleManager.Instance.battlePanel.ReceiveSkillCastMessage(heroUid, skillType);
            if (callback != null)
            {
                callback.OnSkillEnqueue(this);
            }
        }

        public virtual void Do()
        {
            _status = SkillStatus.Doing;
            this.IsCasted = true;
            PlaySkillAnimation();
            PlaySkillAudio();
            
            if (callback != null)
            {
                callback.OnSkillBegin(this);
            }
        }

        public virtual void Done()
        {
            _status = SkillStatus.Done;
            ForceHideSkillParticle();

            if (callback != null)
            {
                callback.OnSkillEnd(this);
            }
        }

        public void OnSkillRelease(BattleSkillRelease bsr, BattleCharacter target)
        {
            if (callback != null)
            {
                callback.OnSkillRelease(bsr, target);
            }
        }


        public virtual bool IsSkillCanCast()
        {
            return !IsCasted && isCanCast;
        }
        public virtual bool IsSkillCanCast4UI()
        {
            return !IsPressed && isCanCast;
        }

        public virtual void Tick()
        {
            audioCtrl.Tick();
        }


        #region Callback
        IBattleSkillCallback callback = null;
        public void RegistBattleSkillCallback(IBattleSkillCallback callback)
        {
            this.callback = callback;
        }
        public void UnRegistBattleSkillCallback()
        {
            callback = null;
        }
        #endregion

    }


}